package com.dd.ent.car.common.player;

import android.graphics.SurfaceTexture;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.view.SurfaceHolder;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Author:LiuJianSheng
 * Date:2016/7/27
 */
public class AsyncMediaPlayer implements PlayerListener, MediaPlayerStateChangeListener {
    private static final int WHAT_UPDATE_CURRENT_POSITION = 0x02;
    private static final int UPDATE_POSITION_DELAY = 500;

    private final AtomicReference<PlayerMessageState> mMessageState = new AtomicReference<>(PlayerMessageState.IDLE);
    private MediaPlayerWrapper mediaPlayer;
    private HandlerThread mHandlerThread;
    private Handler mMessageHandler;
    private Handler mMainHandler = new Handler(Looper.getMainLooper());
    private AtomicInteger mCurrentPlayPosition = new AtomicInteger(0);
    private AtomicInteger mCurrentBufferedPosition = new AtomicInteger(0);
    private AtomicInteger mDuration = new AtomicInteger(0);
    private PlayerListener mPlayerListener;

    public AsyncMediaPlayer() {
        mediaPlayer = new MediaPlayerWrapper();
        mediaPlayer.setPlayerListener(this);
        mediaPlayer.addStateChangeListener(this);
        mHandlerThread = new HandlerThread("media_player");
        mHandlerThread.start();
        mMessageHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case WHAT_UPDATE_CURRENT_POSITION:
                        doUpdateCurrentPosition();
                        break;
                }
            }
        };
    }

    private void doUpdateCurrentPosition() {
        int currentPos = mediaPlayer.getCurrentPosition();
        if (currentPos >= 0) {
            mCurrentPlayPosition.set(currentPos);
            onPlayPositionChange(currentPos);
        }
        mMessageHandler.sendEmptyMessageDelayed(WHAT_UPDATE_CURRENT_POSITION, UPDATE_POSITION_DELAY);
    }

    public void startUpdatePositionLoop() {
        stopUpdatePositionLoop();
        mMessageHandler.sendEmptyMessage(WHAT_UPDATE_CURRENT_POSITION);
    }

    public void stopUpdatePositionLoop() {
        if (mMessageHandler.hasMessages(WHAT_UPDATE_CURRENT_POSITION)) {
            mMessageHandler.removeMessages(WHAT_UPDATE_CURRENT_POSITION);
        }
    }

    public void setDataSourceAndPrepare(String path) {
        if (getState() != MediaPlayerState.IDLE) {
            reset();
        }
        mMessageState.set(PlayerMessageState.SETTING_DATA_SOURCE);
        mMessageHandler.post(new SetDataSourceAndPrepareMessage(mediaPlayer, path));
    }

    public void start() {
        mMessageState.set(PlayerMessageState.STARTING);
        mMessageHandler.post(new StartMessage(mediaPlayer));
    }

    public void pause() {
        mMessageState.set(PlayerMessageState.PAUSING);
        mMessageHandler.post(new PauseMessage(mediaPlayer));
    }

    public void reset() {
        clearAllMessage();
        mMessageState.set(PlayerMessageState.RESETTING);
        mMessageHandler.post(new ResetMessage(mediaPlayer));
    }

    public void stop() {
        clearAllMessage();
        mMessageState.set(PlayerMessageState.STOPPING);
        mMessageHandler.post(new StopMessage(mediaPlayer));
    }

    public void release() {
        clearAllMessage();
        mMessageState.set(PlayerMessageState.RELEASING);
        mMessageHandler.post(new ReleaseMessage(mediaPlayer));
    }

    public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
        mMessageHandler.post(new SetSurfaceMessage(mediaPlayer, mMessageState, surfaceTexture));
    }

    public void setDisplay(SurfaceHolder holder) {
//        mediaPlayer.setDisplay(holder);
        mMessageHandler.post(new SetDisplayMessage(mediaPlayer, mMessageState, holder));
    }

    private void clearAllMessage() {
        mMessageHandler.removeCallbacksAndMessages(null);
        mMessageState.set(PlayerMessageState.IDLE);
    }

    public void setPlayerListener(PlayerListener playerListener) {
        this.mPlayerListener = playerListener;
    }

    public void addStateChangeListener(MediaPlayerStateChangeListener listener) {
        mediaPlayer.addStateChangeListener(listener);
    }

    public void removeStateChangeListener(MediaPlayerStateChangeListener listener) {
        mediaPlayer.removeStateChangeListener(listener);
    }

    public MediaPlayerState getState() {
        return mediaPlayer.getState();
    }

    public boolean isPrepared() {
        return mediaPlayer.isPrepared();
    }

    public int getCurrentPosition() {
        return mCurrentPlayPosition.get();
    }

    public int getCurrentBufferingPosition() {
        return mCurrentBufferedPosition.get();
    }

    public void setVolume(float leftVolume, float rightVolume) {
        mMessageHandler.post(new SetVolumeMessage(mediaPlayer, mMessageState, leftVolume, rightVolume));
    }

    public void attachAuxEffect(int effectId) {
        mMessageHandler.post(new AttachAuxEffectMessage(mediaPlayer, mMessageState, effectId));
    }

    public int getDuration() {
        //解决某些情况下为时长一直为0的问题
        if(mDuration.get() <= 0){
            mDuration.set(mediaPlayer.getDuration());
        }
        return mDuration.get();
    }

    public void seekTo(int position) {
        //断网时，不允许超过已缓存buff大小,会导致ANR
//        if (!NetworkHelper.isNetworkAvailable(BrothersApplication.getInstance()) && position >= mCurrentBufferedPosition.get()) {
//            return;
//        }
//        mediaPlayer.seekTo(position);
        //必须立刻赋值给mCurrentPlayPosition
        //否则replay的时候会出现与实际不对应的情况
        mCurrentPlayPosition.set(position);
        mMessageHandler.post(new SeekToPositionMessage(mediaPlayer, mMessageState, position));
    }

    @Override
    public void onBufferingUpdate(MediaPlayerWrapper mp, int percent) {
        int currentBufferedPosition = getDuration() * percent / 100;
        mCurrentBufferedPosition.set(currentBufferedPosition);
        if (mPlayerListener != null) {
            mPlayerListener.onBufferingUpdate(mp, percent);
        }
    }

    @Override
    public void onCompletion(MediaPlayerWrapper mp) {
//        seekTo(0);
        onPlayPositionChange(getDuration());
        if (mPlayerListener != null) {
            mPlayerListener.onCompletion(mp);
        }
    }

    @Override
    public boolean onError(MediaPlayerWrapper mp, int what, int extra) {
        if (mPlayerListener != null) {
            return mPlayerListener.onError(mp, what, extra);
        }
        return true;
    }

    @Override
    public boolean onInfo(MediaPlayerWrapper mp, int what, int extra) {
        if (mPlayerListener != null) {
            return mPlayerListener.onInfo(mp, what, extra);
        }
        return true;
    }

    @Override
    public void onVideoSizeChanged(MediaPlayerWrapper mp, int width, int height) {
        if (mPlayerListener != null) {
            mPlayerListener.onVideoSizeChanged(mp, width, height);
        }
    }

    @Override
    public void onPrepared(MediaPlayerWrapper mp) {
        int duration = mediaPlayer.getDuration();
        mDuration.set(duration);
        if (mPlayerListener != null) {
            mPlayerListener.onPrepared(mp);
        }
    }

    @Override
    public void onPlayPositionChange(final int newPosition) {
        if (mPlayerListener != null) {
            callbackOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mPlayerListener.onPlayPositionChange(newPosition);
                }
            });
        }
    }

    @Override
    public void onSeekComplete(MediaPlayerWrapper mp) {
        if (mPlayerListener != null) {
            mPlayerListener.onSeekComplete(mp);
        }
    }

    @Override
    public void onStateChange(MediaPlayerState oldState, MediaPlayerState newState) {
        stopUpdatePositionLoop();
        switch (newState) {
            case IDLE:
            case STOPPED:
            case RELEASE:
                resetParams();
                break;
            case STARTED:
                startUpdatePositionLoop();
                break;
        }
    }

    private void resetParams() {
        mDuration.set(0);
        mCurrentBufferedPosition.set(0);
        mCurrentPlayPosition.set(0);
        setMessageState(PlayerMessageState.IDLE);
    }

    private void setMessageState(PlayerMessageState state) {
        mMessageState.set(state);
    }

    public PlayerMessageState getMessageState() {
        return mMessageState.get();
    }

    public boolean isPaused() {
        return getState() == MediaPlayerState.PAUSED || getMessageState() == PlayerMessageState.PAUSING;
    }

    public boolean isStarted() {
        return getState() == MediaPlayerState.STARTED || getMessageState() == PlayerMessageState.STARTING;
    }

    public boolean isIdle() {
        return getState() == MediaPlayerState.IDLE || getMessageState() == PlayerMessageState.RESETTING || getMessageState() == PlayerMessageState.IDLE;
    }

    private void callbackOnUiThread(Runnable runnable) {
        //boolean isInUiThread = MediaPlayerUtils.isInUiThread();
        boolean isInUiThread = false;
        if (isInUiThread) {
            runnable.run();
        } else {
            mMainHandler.post(runnable);
        }
    }
}
